/*
except 接口实现了 C 语言简单的结构化异常处理。
目前的吭是在 TRY - END_TRY 块中，需要使用 RETURN 宏退出。
非线程安全，不能用于多线程。
**/

#ifndef _EXCEPT_H_
#define _EXCEPT_H_
#include <stdio.h>
#include <setjmp.h>


#define T Except_T
typedef struct T {
	const char *msg;
} T;

typedef struct except_Frame except_Frame;
struct except_Frame {
	const T *except;
	const char *file;
	int line;
	jmp_buf env;

	except_Frame *prev; // 指向前一个调用栈s
};


enum {
	except_ENTER = 0,
	except_RAISED,
	except_HANDLED,
	except_FINAL,
};


extern except_Frame *__ex_frame;
void except_raise(const T *ex, const char *file, int line);


#define RAISE(ex) \
	except_raise(&ex, __FILE__, __LINE__)
#define RERAISE \
	except_raise(__frame.except, __frame.file, __frame.line)

#define TRY do { \
	volatile int __flag; \
	except_Frame __frame; \
	__frame.prev = __ex_frame; \
	__ex_frame = &__frame; \
	__flag = setjmp(__frame.env); \
	if (__flag == except_ENTER) {

// 注意 if 分支用于处理若没有异常，则从链表中移除 frame
#define EXCEPT(ex) \
		if (__flag == except_ENTER) \
			__ex_frame = __frame.prev; \
	} else if (__frame.except == &ex) { \
			__flag = except_HANDLED; 

#define ELSE \
		if (__flag == except_ENTER) \
			__ex_frame = __frame.prev; \
	} else { \
		__flag = except_HANDLED;
	
#define FINALLY \
		if (__flag == except_ENTER) \
			__ex_frame = __frame.prev; \
	} { \
		if (__flag == except_ENTER) \
			__flag = except_FINAL;

#define END_TRY \
		if (__flag == except_ENTER) \
			__ex_frame = __frame.prev; \
	} \
	if (__flag == except_RAISED) \
		RERAISE; \
	} while (0); // end for TRY

// RETURN 只能用于在 TRY 快内的正常逻辑
#define RETURN \
	switch(__ex_frame = __frame.prev, 0) default: return;
// 用于 EXCEPT ELSE 和 FINALLY 中访问异常，在 FINALLY 中可能是没有异常的需要额外的判断
#define EXCEPT_MSG (__frame.except ? __frame.except->msg : NULL)
#define EXCEPT_FILE (__frame.file)
#define EXCEPT_LINE (__frame.line)

#undef T

#endif // _EXCEPT_H_
